/*
 * @Author: wuqingchun
 * @Date: 2024-07-29 15:52:37
 * @Description: epoll 事件调度器实现
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-07-31 17:32:30
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include <sys/epoll.h>

#include "ev_log.h"
#include "ev_struct.h"
#include "ev_signal.h"
#include "ev_dispatcher.h"


typedef struct tagEvEpollDispatcher
{
    EV_DISPATCHER_S stBase;
    struct epoll_event astEvents[1024];
    int iEpollFd;
}EV_EPOLL_DISPATCHER_S;


EV_DISPATCHER_S* EV_epoll_Create()
{
    EV_EPOLL_DISPATCHER_S* pstEpollDP = malloc(sizeof(EV_EPOLL_DISPATCHER_S));
    if (pstEpollDP == NULL)
    {
        return NULL;
    }

    /*Since Linux 2.6.8, the size argument is ignored, but must be greater than zero;*/
    int iFd = epoll_create(1);
    if (iFd == -1)
    {
        free(pstEpollDP);
        return NULL;
    }

    pstEpollDP->iEpollFd = iFd;
    int iErr = EV_signal_Init(&pstEpollDP->stBase);
    
    return &pstEpollDP->stBase;
}

void EV_epoll_Destroy(EV_DISPATCHER_S* pstDP)
{

}

int EV_epoll_Dispatch(EV_DISPATCHER_S* pstDP)
{
    EV_EPOLL_DISPATCHER_S* pstEpollDP = (EV_EPOLL_DISPATCHER_S*)pstDP;
    int iTimeout = -1;

    int iEventNum = epoll_wait(pstEpollDP->iEpollFd, pstEpollDP->astEvents, 1024, iTimeout);
    
    printf("EventNum: %d\n", iEventNum);

    if (iEventNum == -1)
    {
        if (errno != EINTR) 
        {
            return -1;
        }

        return 0;
    }

    struct epoll_event* pstEpEv;
    for (int i = 0; i < iEventNum; i++)
    {
        pstEpEv = &pstEpollDP->astEvents[i];
        printf("%d, 0x%x\n", pstEpEv->data.fd, pstEpEv->events);

        pstDP->stSigEvent.pfCallback(pstEpEv->data.fd, pstDP);
    }

    return 0;
}

int EV_epoll_AddEvent(EV_DISPATCHER_S* pstDP, EV_EVENT_S* pstEvent)
{
    EV_EPOLL_DISPATCHER_S* pstEpollDP = (EV_EPOLL_DISPATCHER_S*)pstDP;
    struct epoll_event stEpEvent;

    stEpEvent.data.fd = pstEvent->iEventFd;
    stEpEvent.events = EPOLLIN;

    LOG_INFO("AddEvent, fd=%d, events=0x%x", pstEvent->iEventFd, stEpEvent.events);
    
    return epoll_ctl(pstEpollDP->iEpollFd, EPOLL_CTL_ADD, pstEvent->iEventFd, &stEpEvent);
}

EV_DISPATCHER_OPS_S g_stEvEpollOps = 
{
    .pcName = "epoll",
    .Create = EV_epoll_Create,
    .Destroy = EV_epoll_Destroy,
    .Dispatch = EV_epoll_Dispatch,
    .AddEvent = EV_epoll_AddEvent,
};